package com.zheng.hr.rpc.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zheng.common.annotation.BaseService;

import com.zheng.common.util.PropertiesFileUtil;
import com.zheng.common.util.TimeUtil;
import com.zheng.common.util.WeixinUtil;
import com.zheng.hr.dao.model.*;
import com.zheng.hr.dao.mapper.HrApprovalMapper;
import com.zheng.hr.rpc.api.*;
import com.zheng.common.base.BaseServiceImpl;
import com.zheng.oa.common.utils.TimeStampUtil;
import com.zheng.upms.dao.model.UpmsUser;
import com.zheng.upms.rpc.api.UpmsUserService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 审批表 服务实现类
 * </p>
 *
 * @author likun
 * @since 2018-04-28
 */
@Service
@Transactional(rollbackFor = Exception.class)
@BaseService
public class HrApprovalServiceImpl extends BaseServiceImpl<HrApprovalMapper, HrApproval> implements HrApprovalService {
    private final static Logger _log = LoggerFactory.getLogger(HrApprovalService.class);

    @Autowired
    private HrPaidLeaveService paidLeaveService;
    @Autowired
    private HrDictService dictService;
    @Autowired
    private HrCheckinService checkinService;
    @Autowired
    private UpmsUserService userService;
    @Autowired
    private HrAttendanceService attendanceService;
    @Autowired
    private HrPersonalRecordsService personalRecordsService;
    @Autowired
    private HrFestivalService festivalService;
    @Autowired
    private HrApprovalService approvalService;

    /**
     * 同步所有审核
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    @Override
    public boolean refreshApproval(long beginTime, long endTime) {
        //获取所有时间段内审核信息
        JSONArray approvalArray = WeixinUtil.getApprovalArray(beginTime, endTime);
        EntityWrapper<HrApproval> approvalEntityWrapper;
        Calendar instance = Calendar.getInstance();
        //最后遍历出的审核列表
        List<HrApproval> approvals = new ArrayList<>();
        for (int i = 0; i < approvalArray.size(); i++) {
            JSONObject approvalJSON = approvalArray.getJSONObject(i);
            String sp_num = approvalJSON.getString("sp_num");
            Integer sp_status = approvalJSON.getInteger("sp_status");

            approvalEntityWrapper = new EntityWrapper<>();
            approvalEntityWrapper.eq("sp_num", sp_num);
            HrApproval approval = selectOne(approvalEntityWrapper);
            if (approval == null) {
                //如果已经加入了该审核，只需要改变状态，否则新建审核信息
                approval = new HrApproval();
            } else if (!approval.getSpStatus().equals(HrApproval.APPROVAL_STATUS) || sp_status.equals(HrApproval.APPROVAL_STATUS)) {
                //如果不是审查中或当前仍在审核，就不再修改
                continue;
            }
            approval.setSpStatus(sp_status);
            approval.setSpNum(sp_num);
            approval.setApplyUserName(approvalJSON.getString("apply_user_id"));
            approval.setApplyName(approvalJSON.getString("apply_name"));
            approval.setApplyOrg(approvalJSON.getString("apply_org"));
            approval.setApplyTime(TimeStampUtil.timeStampChange(approvalJSON.getLong("apply_time")));
            approval.setApprovalName(approvalJSON.getString("approval_name"));
            approval.setSpName(approvalJSON.getString("spname"));
            try {
                String reason = approvalJSON.getJSONObject("leave").getString("reason");
                approval.setReason(reason);
            } catch (Exception e) {
            }
            try {
                String durationDay = approvalJSON.getJSONObject("comm").getJSONObject("apply_data").
                        getJSONObject("duration").getString("durationDay");
                Double day = Double.parseDouble(durationDay);
                approval.setDurationDay(day);
                //如果是加班，就添加加班记录
                if (approval.getSpName().equals("加班")) {
                    String durationHour = approvalJSON.getJSONObject("comm").getJSONObject("apply_data").
                            getJSONObject("duration").getString("durationHour");
                    Double hour = Double.parseDouble(durationHour);
                    approval.setDurationHour(hour.intValue());
                    //如果通过审核
                    if (sp_status.equals(HrApproval.PASS_STATUS)) {
                        //添加加班记录
                        try {
                            paidLeaveService.insertOverTimePaidLeave(day, hour.intValue(), approval.getApplyUserName());
                        } catch (Exception e) {
                            e.printStackTrace();
                            return false;
                        }
                    }
                    //如果是年假或者调休，就减少对应的记录
                } else if (StringUtils.isNotBlank(approval.getReason()) && sp_status.equals(HrApproval.PASS_STATUS)) {
                    EntityWrapper<HrPaidLeave> paidLeaveEntityWrapper;
                    if (approval.getReason().equals("年假")) {
                        String yearValue = dictService.getDictValue("年假", "leave_type", "1");
                        int year = instance.get(Calendar.YEAR);
                        paidLeaveEntityWrapper = new EntityWrapper<>();
                        paidLeaveEntityWrapper.eq("year", year).eq("username", approval.getApplyUserName()).eq("type", yearValue);
                        HrPaidLeave yearPaidLeave = paidLeaveService.selectOne(paidLeaveEntityWrapper);
                        if (null == yearPaidLeave) {
                            approval.setReason("事假");
                            approval.setSpStatus(HrApproval.YEAR_LEAVE_STATUS);
                        }
                        Double yearPaidLeaveDays = yearPaidLeave.getDays();
                        Double yearPaidLeaveUsedDays = yearPaidLeave.getUsedDays();
                        Double leftDay = yearPaidLeaveDays - yearPaidLeaveUsedDays;
                        //判断所请年假是否小于年假，如果小于就设置为事假
                        if (leftDay < day) {
                            approval.setReason("事假");
                            approval.setSpStatus(HrApproval.YEAR_LEAVE_STATUS);
                        } else {
                            yearPaidLeave.setUsedDays(yearPaidLeaveUsedDays + day);
                            paidLeaveService.updateById(yearPaidLeave);
                        }
                    } else if (approval.getReason().equals("调休假")) {
                        String offValue = dictService.getDictValue("调休假", "leave_type", "0");
                        paidLeaveEntityWrapper = new EntityWrapper<>();
                        paidLeaveEntityWrapper.eq("username", approval.getApplyUserName()).eq("type", offValue);
                        HrPaidLeave offPaidLeave = paidLeaveService.selectOne(paidLeaveEntityWrapper);
                        if (offPaidLeave != null) {
                            Double offPaidLeaveDays = offPaidLeave.getDays();
                            Double offPaidLeaveUsedDays = offPaidLeave.getUsedDays();
                            Double leftDay = offPaidLeaveDays - offPaidLeaveUsedDays;
                            if (leftDay < day) {
                                approval.setReason("事假");
                                approval.setSpStatus(HrApproval.OFF_LEAVE_STATUS);

                            } else {
                                offPaidLeave.setUsedDays(offPaidLeaveUsedDays + day);
                                paidLeaveService.updateById(offPaidLeave);
                            }
                        } else {
                            approval.setReason("事假");
                            approval.setSpStatus(HrApproval.OFF_LEAVE_STATUS);
                        }
                    }
                }
            } catch (Exception e) {
            }
            try {
                Long approvalBeginTime = approvalJSON.getJSONObject("comm").getJSONObject("apply_data").
                        getJSONObject("begin_time").getLong("value");
                approval.setBeginTime(TimeStampUtil.timeStampChange(approvalBeginTime));
            } catch (Exception e) {
            }
            try {
                Long approvalEndTime = approvalJSON.getJSONObject("comm").getJSONObject("apply_data").
                        getJSONObject("end_time").getLong("value");
                approval.setEndTime(TimeStampUtil.timeStampChange(approvalEndTime + 12 * 60 * 60 * 1000));
            } catch (Exception e) {
            }
            try {
                Long checkInTime = approvalJSON.getJSONObject("comm").getJSONObject("apply_data").
                        getJSONObject("checkin-time").getLong("value");
                String checkInStatus = approvalJSON.getJSONObject("comm").getJSONObject("apply_data").
                        getJSONObject("checkin-status").getString("value");
                instance.setTimeInMillis(checkInTime);
                instance.set(instance.get(Calendar.YEAR), instance.get(Calendar.MONTH), instance.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
                if (!checkInStatus.contains("(")) {
                    approval.setCheckinTime(checkInTime);
                } else {
                    String time = checkInStatus.substring(checkInStatus.indexOf("(") + 1, checkInStatus.indexOf(")"));
                    String[] hm = time.split(":");
                    //小时转毫秒
                    Long hourM = Long.parseLong(hm[0]) * 60 * 60 * 1000;
                    //分钟转毫秒
                    Long MinuteM = Long.parseLong(hm[1]) * 1000 * 60;
                    approval.setCheckinTime(instance.getTimeInMillis() + hourM + MinuteM);
                }
                approval.setCheckinStatus(checkInStatus);
            } catch (Exception e) {
            }
            approvals.add(approval);
        }
        if (approvals.size() < 1) {
            return true;
        }
        return insertOrUpdateBatch(approvals);
    }

    private void getNowApproval() {
        Date now = new Date();
        Calendar instance = Calendar.getInstance();
        instance.setTime(now);
        long endTime = instance.getTimeInMillis();
        //月份不好算 计算3个31就好
        instance.add(Calendar.MONTH, -3);
        int month = instance.get(Calendar.MONTH);
        int year = instance.get(Calendar.YEAR);
        instance.set(year, month, 1);
        long startTime = instance.getTimeInMillis();
        refreshApproval(startTime / 1000, endTime / 1000);
    }

    private HrApproval getNowMonthDate(HrApproval approval, int year, int month) {
        Long beginTime = approval.getBeginTime();
        Long endTime = approval.getEndTime();
        if (beginTime == null || endTime == null) {
            return approval;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(beginTime);
        int beginMonth = calendar.get(Calendar.MONTH);
        int beginMonthMaxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        int beginDay = calendar.get(Calendar.DAY_OF_MONTH);
        int beginHour = calendar.get(Calendar.HOUR_OF_DAY);
        calendar.setTimeInMillis(endTime);
        int endMonth = calendar.get(Calendar.MONTH);
        int endDay = calendar.get(Calendar.DAY_OF_MONTH);
        int endHour = calendar.get(Calendar.HOUR_OF_DAY);
        //如果起始结束一个月，结束
        if (beginMonth == endMonth) {
            return approval;
        }
        Double nowMonthDurationDay = 0D;
        //如果结束在下个月，获取到月底所剩天数
        if (beginMonth == month) {
            //需要加一天（月末当天）
            nowMonthDurationDay = (double) (beginMonthMaxDays - beginDay) + 1;
            if (beginHour != 0) {
                //如果非0点开始请假，那么第一天就是半天
                nowMonthDurationDay = nowMonthDurationDay - 0.5;
            }
            //将结束时间设置为下月1号0点
            calendar.set(year, month + 1, 1, 0, 0, 0);
            approval.setEndTime(calendar.getTimeInMillis());
        } else {
            //如果结束在当月，获取月初到本日所剩天数
            calendar.set(year, month, 1, 0, 0, 0);
            int nowMonthFirstDay = calendar.get(Calendar.DAY_OF_MONTH);
            nowMonthDurationDay = (double) (endDay - nowMonthFirstDay);
            if (endHour != 0) {
                //如果非0点开始请假，那么多加最后半天日期
                nowMonthDurationDay = nowMonthDurationDay + 0.5;
            }
            //将开始时间设置为本月1号0点
            calendar.set(year, month, 1, 0, 0, 0);
            approval.setBeginTime(calendar.getTimeInMillis());
        }
        approval.setDurationDay(nowMonthDurationDay);
        return approval;
    }

    @Override
    public boolean countAttendance(int year, int month) {
        //每次同步的时候 先获取当前三个月的审核记录
        getNowApproval();
        //获取到需要添加周日调休的部门
        String weekOrganizationId = PropertiesFileUtil.getInstance().get("weekOrganizationId");
        //获取到每周调休的时间
        String weekDay = PropertiesFileUtil.getInstance().get("weekDay");
        List<Integer> organizationIds = new ArrayList<>();
        for (String idStr : weekOrganizationId.split(",")) {
            organizationIds.add(Integer.parseInt(idStr));
        }
        double weekDays = Double.parseDouble(weekDay);

        boolean result = false;
        //calendar 的月份要-1
        month = month - 1;
        //获取选择的月份的时间戳范围
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, 1, 0, 0, 0);
        //获取法定假日date
        Date festivalDate = calendar.getTime();

        long beginTime = calendar.getTimeInMillis();
        final int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(year, month, day, 23, 59, 59);
        long endTime = calendar.getTimeInMillis();
        //获取时间范围内所有的考勤内容和审批内容
        EntityWrapper<HrCheckin> checkinEntityWrapper;
        EntityWrapper<HrApproval> approvalEntityWrapper = new EntityWrapper<>();
        approvalEntityWrapper.where("(begin_time >= " + beginTime + " and begin_time < " + endTime + ")" +
                " or (end_time>= " + beginTime + " and end_time <" + endTime + ")").andNew("sp_status >= 2 and sp_status != 4 and sp_status != 3");
        //获取请假审核
        List<HrApproval> leaveApproval = selectList(approvalEntityWrapper);
        approvalEntityWrapper = new EntityWrapper<>();
        approvalEntityWrapper.where("checkin_time >= " + beginTime + " and checkin_time < " + endTime)
                .andNew("sp_status =2");
        //获取签到审核
        List<HrApproval> checkInApproval = selectList(approvalEntityWrapper);

        List<HrApproval> approvals = new ArrayList<>();
        approvals.addAll(leaveApproval);
        approvals.addAll(checkInApproval);

        //获取本月法定假期时间
        SimpleDateFormat festivalSdf = new SimpleDateFormat("yyyy-MM");
        String festivalDateStr = festivalSdf.format(festivalDate);

        List<HrFestival> hrFestivals = festivalService.selectList(new EntityWrapper<HrFestival>()
                .eq("DATE_FORMAT(festival_date,'%Y-%m')", festivalDateStr));
        //获取中午打卡时间
        String checkTime = dictService.getDictValue("check", "check_time", "13:00:00");
        checkTime = "'" + checkTime + "'";
        //根据审批信息 修正所有异常签到信息
        for (HrApproval approval : approvals) {
            String spName = approval.getSpName();
            if (spName.equals("非正常签到")) {
                Long checkinTime = approval.getCheckinTime();
                checkinEntityWrapper = new EntityWrapper<>();
                checkinEntityWrapper.where("checkin_time=" + checkinTime).
                        and("user_name=" + approval.getApplyUserName());
                HrCheckin checkin = checkinService.selectOne(checkinEntityWrapper);
                if (checkin == null) {
                    continue;
                }
                checkin.setState(HrCheckin.VERIFIED_STATE);
                checkinService.updateById(checkin);
            } else if (!spName.equals("加班")) {
                //请假、出差等
                Long approvalBeginTime = approval.getBeginTime();
                Long approvalEndTime = approval.getEndTime();
                checkinEntityWrapper = new EntityWrapper<>();
                checkinEntityWrapper.where("checkin_time>=" + approvalBeginTime).and("checkin_time<=" + approvalEndTime).
                        and("user_name=" + approval.getApplyUserName()).and("exception_type != ''");
                List<HrCheckin> checkinList = checkinService.selectList(checkinEntityWrapper);
                for (HrCheckin checkin : checkinList) {
                    checkin.setState(HrCheckin.VERIFIED_STATE);
                    checkinService.updateById(checkin);
                }
            }
        }

        //获取所有用户的信息
        EntityWrapper<UpmsUser> userEntityWrapper = new EntityWrapper<>();
        userEntityWrapper.where("real_user=" + UpmsUser.IS_REAL_USER);
        List<UpmsUser> userList = userService.selectList(userEntityWrapper);
        //转换日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date(beginTime);
        String time = sdf.format(date);

        for (UpmsUser user : userList) {
            //获取用户信息
            Map<String, Object> personalRecordsInfo = personalRecordsService.getPersonalRecordsInfo(user.getUserId());
            //如果用户在本月入职，修改入职前考勤记录的状态
            JSONObject remark = new JSONObject();
            EntityWrapper<HrAttendance> attendanceEntityWrapper = new EntityWrapper<>();
            attendanceEntityWrapper.where("time='" + time + "'").eq("user_name", user.getUsername());
            HrAttendance attendance;
            //获取到用户的考勤记录
            attendance = attendanceService.selectOne(attendanceEntityWrapper);
            if (attendance == null) {
                attendance = new HrAttendance();
                attendance.setTime(new Date(beginTime));
                attendance.setUserName(user.getUsername());
            }
            //各种次数天数数据
            //应打卡天数
            Double supposedDays = 0d;
            //实际打卡天数
            Double actualDays = 0d;
            //异常打卡天数
            Double exceptionDays = 0d;
            //应打卡次数
            Integer supposedCount = 0;
            //实际打卡次数
            Integer actualCount = 0;
            //异常打卡次数
            Integer exceptionCount = 0;
            //请假天数
            Double leaveDays = 0d;
            //补卡次数
            Integer supplementCount = 0;
            //出差天数
            Double travelDays = 0d;
            //外出天数
            Double outDays = 0d;
            //加班小时
            Integer overtimeHours = 0;
            //加班天数
            Integer overtimeDays = 0;
            //年假天数
            Double annualLeaveDays = 0d;
            //事假天数
            Double normalLeaveDays = 0d;
            //病假天数
            Double sickLeaveDays = 0d;
            //调休假天数
            Double offLeaveDays = 0d;
            //婚假天数
            Double maritalLeaveDays = 0d;
            //婚假天数
            Double maternityLeaveDays = 0d;
            //陪产假天数
            Double paternityLeaveDays = 0d;
            //其他假期天数
            Double otherLeaveDays = 0d;
            //找到所有当前用户的请假信息
            List<HrApproval> userApprovals = approvals.stream().
                    filter(approval -> approval.getApplyUserName().equals(user.getUsername())).collect(Collectors.toList());
            for (HrApproval approval : userApprovals) {
                // 如果请假等信息是跨月，只获取本月的请假天数
                approval = getNowMonthDate(approval, year, month);
                String reason = approval.getReason();
                String spName = approval.getSpName();
                Long bTime = approval.getBeginTime();
                Long eTime = approval.getEndTime();
                if (bTime == null || eTime == null) {
                    continue;
                }
                Double approvalBeginTime = (double) (bTime / 1000);
                Double approvalEndTime = (double) (eTime / 1000);
                Double durationDay = (approvalEndTime - approvalBeginTime) / (60 * 60 * 24);
                Double durationHour = (approvalEndTime - approvalBeginTime) / (60 * 60);
                if (null == durationDay) {
                    durationDay = 0d;
                }
                if (spName.equals("加班")) {
                    overtimeHours += durationHour.intValue();
                    overtimeDays += durationDay.intValue();
                } else if (spName.equals("出差")) {
                    travelDays += durationDay;
                } else if (spName.equals("外出")) {
                    outDays += durationDay;
                } else if (spName.equals("非正常签到")) {
                    supplementCount++;
                } else if (reason.equals("年假")) {
                    annualLeaveDays += durationDay;
                } else if (reason.equals("事假")) {
                    normalLeaveDays += durationDay;
                    leaveDays += durationDay;
                } else if (reason.equals("病假")) {
                    sickLeaveDays += durationDay;
                    leaveDays += durationDay;
                } else if (reason.equals("婚假")) {
                    maritalLeaveDays += durationDay;
                    leaveDays += durationDay;
                } else if (reason.equals("陪产假")) {
                    paternityLeaveDays += durationDay;
                    leaveDays += durationDay;
                } else if (reason.equals("调休假")) {
                    offLeaveDays += durationDay;
                } else if (reason.equals("其他")) {
                    otherLeaveDays += durationDay;
                    leaveDays += durationDay;
                }
            }
            //获取到调休转事假的记录
            List<HrApproval> offLeaveErrorApprovals = leaveApproval.stream().
                    filter(approval -> approval.getSpStatus().equals(HrApproval.OFF_LEAVE_STATUS)
                            && approval.getApplyUserName().equals(user.getUsername()))
                    .collect(Collectors.toList());
            //获取到调休转事假的记录
            List<HrApproval> yearLeaveErrorApprovals = leaveApproval.stream().
                    filter(approval -> approval.getSpStatus().equals(HrApproval.YEAR_LEAVE_STATUS)
                            && approval.getApplyUserName().equals(user.getUsername())).collect(Collectors.toList());
            if (offLeaveErrorApprovals.size() > 0) {
                Double offLeaveErrorDays = 0D;
                for (HrApproval approval : offLeaveErrorApprovals) {
                    offLeaveErrorDays += approval.getDurationDay();
                }
                remark.put("offLeaveErrorDays", offLeaveErrorDays);
            }
            if (yearLeaveErrorApprovals.size() > 0) {
                Double yearLeaveErrorDay = 0D;
                for (HrApproval approval : yearLeaveErrorApprovals) {
                    yearLeaveErrorDay += approval.getDurationDay();
                }
                remark.put("yearLeaveErrorDays", yearLeaveErrorDay);
            }

            //用户打卡信息
            checkinEntityWrapper = new EntityWrapper<>();
            checkinEntityWrapper.where("checkin_time >=" + beginTime).and("checkin_time<=" + endTime)
                    .eq("user_name", user.getUsername());
            List<HrCheckin> userCheckinList = checkinService.selectList(checkinEntityWrapper);
            //获取异常打卡信息
            List<HrCheckin> exceptionCheckin = userCheckinList.stream().filter(
                    checkin -> checkin.getState().equals(HrCheckin.UNVERIFIED_STATE) &&
                            StringUtils.isNotBlank(checkin.getExceptionType())).collect(Collectors.toList());

            //如果该用户属于调休部门，减少每月调休对应的异常天数
            boolean isBreakOrganization = false;
            for (Integer organizationId : organizationIds) {
                if (user.getOrganizationId().equals(organizationId)) {
                    isBreakOrganization = true;
                    if (personalRecordsInfo != null) {
                        int sundayOfMonth;
                        if (personalRecordsInfo.get("joinedTime") != null) {
                            Date joinedTime = (Date) personalRecordsInfo.get("joinedTime");
                            calendar.setTime(joinedTime);
                            int joinYear = calendar.get(Calendar.YEAR);
                            int joinMonth = calendar.get(Calendar.MONTH);
                            calendar.set(year, month, 1);
                            int thisYear = calendar.get(Calendar.YEAR);
                            int thisMonth = calendar.get(Calendar.MONTH);
                            if (joinYear == thisYear && joinMonth == thisMonth) {
                                sundayOfMonth = TimeUtil.getSundayOfMonth(joinedTime);
                            } else {
                                LocalDate firstDayOfMonth = LocalDate.of(year, month + 1, 1);
                                sundayOfMonth = TimeUtil.getSundayOfMonth(firstDayOfMonth);
                            }
                        } else {
                            LocalDate firstDayOfMonth = LocalDate.of(year, month + 1, 1);
                            sundayOfMonth = TimeUtil.getSundayOfMonth(firstDayOfMonth);
                        }
                        double breakDays = sundayOfMonth * weekDays;
                        //计算国家法定假期
                        double festivalDays = 0d;
                        for (HrFestival festival : hrFestivals) {
                            festivalDays += festival.getFestivalDay();
                        }
                        breakDays = breakDays + festivalDays;

                        int breakCount = (int) breakDays * 4;
                        //计算各种天数，以半天为单位查询
                        checkinEntityWrapper = new EntityWrapper<>();
                        checkinEntityWrapper.where("checkin_time >=" + beginTime)
                                .and("checkin_time<=" + endTime)
                                .eq("user_name", user.getUsername())
                                .and("DATE_FORMAT(checkin_date, '%T') <" + checkTime)
                                .eq("state", HrCheckin.UNVERIFIED_STATE)
                                .eq("exception_type", "未打卡")
                                .groupBy("DATE_FORMAT(checkin_date, '%Y-%m-%d')");
                        List<HrCheckin> beforeCheckTimeNoCheckDayList = checkinService.selectList(checkinEntityWrapper);

                        checkinEntityWrapper = new EntityWrapper<>();
                        checkinEntityWrapper.where("checkin_time >=" + beginTime)
                                .and("checkin_time<=" + endTime)
                                .eq("user_name", user.getUsername())
                                .and("DATE_FORMAT(checkin_date, '%T') >=" + checkTime)
                                .eq("state", HrCheckin.UNVERIFIED_STATE)
                                .eq("exception_type", "未打卡")
                                .groupBy("DATE_FORMAT(checkin_date, '%Y-%m-%d')");
                        List<HrCheckin> afterCheckTimeNoCheckDayList = checkinService.selectList(checkinEntityWrapper);
                        List<HrCheckin> allNoCheckDayList = new ArrayList<>();

                        allNoCheckDayList.addAll(beforeCheckTimeNoCheckDayList);
                        allNoCheckDayList.addAll(afterCheckTimeNoCheckDayList);
                        //半天要乘0.5
                        exceptionDays = allNoCheckDayList.size() * 0.5;
                        //再减去该调休的天数
                        exceptionDays = exceptionDays - breakDays;
                        //获取未打卡次数
                        List<HrCheckin> noCheckList = exceptionCheckin.stream().filter(checkin ->
                                checkin.getExceptionType().equals("未打卡")).collect(Collectors.toList());
                        exceptionCount = noCheckList.size();
                        exceptionCount = exceptionCount - breakCount;
                        supposedDays = (double) userCheckinList.size() / 4;
                        supposedDays = supposedDays - breakDays;
                        //计算应打卡次数
                        supposedCount = (int) (supposedDays * 4);

                    }
                    break;
                }
            }
            //非调休部门
            if (!isBreakOrganization) {
                //应打卡次数
                supposedCount = userCheckinList.size();
                //异常打卡次数
                exceptionCount = exceptionCheckin.size();
                //行政等部门暂时不设置异常打卡应打卡天数
                //判断是否本月入职
                if (personalRecordsInfo != null) {
                    if (personalRecordsInfo.get("joinedTime") != null) {
                        Date joinedTime = (Date) personalRecordsInfo.get("joinedTime");
                        calendar.setTime(joinedTime);
                        int joinYear = calendar.get(Calendar.YEAR);
                        int joinMonth = calendar.get(Calendar.MONTH);
                        calendar.set(year, month, 1);
                        int thisYear = calendar.get(Calendar.YEAR);
                        int thisMonth = calendar.get(Calendar.MONTH);
                        //如果是本月入职，减少该日期前的异常考勤次数
                        if (joinYear == thisYear && joinMonth == thisMonth) {
                            checkinEntityWrapper = new EntityWrapper<>();
                            checkinEntityWrapper.where("checkin_time >=" + beginTime)
                                    .and("checkin_time<=" + joinedTime.getTime())
                                    .eq("user_name", user.getUsername())
                                    .eq("state", HrCheckin.UNVERIFIED_STATE)
                                    .eq("exception_type", "未打卡");
                            //移除异常次数
                            int noJoinCheckinCount = checkinService.selectCount(checkinEntityWrapper);
                            exceptionCount = exceptionCount - noJoinCheckinCount;
                            //移除异常数据
                            exceptionCheckin = exceptionCheckin.stream().filter(
                                    checkin -> checkin.getCheckinTime() >= joinedTime.getTime()).collect(Collectors.toList());
                        }
                    }
                }
                //应打卡天数
                /*
                    checkinEntityWrapper = new EntityWrapper<>();
                    checkinEntityWrapper.where("checkin_time >=" + beginTime).and("checkin_time<=" + endTime)
                            .eq("user_name", user.getUsername()).groupBy("checkin_date");
                    List<HrCheckin> supposedDaysList = checkinService.selectList(checkinEntityWrapper);
                    checkinEntityWrapper.and("exception_type != ''").and("exception_type != '非常用设备'").eq("state", HrCheckin.UNVERIFIED_STATE).
                            groupBy("checkin_date");
                    List<HrCheckin> exceptionDaysList = checkinService.selectList(checkinEntityWrapper);
                    supposedDays = (double) supposedDaysList.size();
                    exceptionDays = (double) exceptionDaysList.size();
                */
            }

            //获取非常用设备次数
            List<HrCheckin> unusual = userCheckinList.stream().filter(
                    checkin -> checkin.getState().equals(HrCheckin.UNVERIFIED_STATE) &&
                            checkin.getExceptionType().equals("非常用设备")).collect(Collectors.toList());
            if (unusual.size() > 0) {
                //将非常用设备信息放入备注
                exceptionCount = exceptionCount - unusual.size();
                JSONArray unusualArray = new JSONArray();
                for (HrCheckin checkin : unusual) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd dd:MM:ss");
                    Date checkInDate = new Date(checkin.getCheckinTime());
                    unusualArray.add("打卡时间：" + simpleDateFormat.format(checkInDate) + "，设备名称" + checkin.getWifiName());
                }
                remark.put("unusualArray", unusualArray);
                attendance.setRemark(remark.toString());
            }
            //将异常类型放入备注
            Integer lateCount = 0;
            Integer notCheckCount = 0;
            for (HrCheckin checkIn : exceptionCheckin) {
                if (checkIn.getExceptionType().equals("时间异常")) {
                    lateCount++;
                } else {
                    notCheckCount++;
                }
            }
            if (isBreakOrganization) {
                //如果是非行政部门，只能用异常天数减去迟到天数来计算未打卡天数
                notCheckCount = exceptionCount;
            }
            remark.put("lateCount", lateCount);
            remark.put("notCheckCount", notCheckCount);

            actualCount = supposedCount - exceptionCount;
            actualDays = supposedDays - exceptionDays;
            //负数替换为0
            supposedDays = supposedDays > 0 ? supposedDays : 0;
            exceptionDays = exceptionDays > 0 ? exceptionDays : 0;
            actualDays = actualDays > 0 ? actualDays : 0;

            supposedCount = supposedCount > 0 ? supposedCount : 0;
            exceptionCount = exceptionCount > 0 ? exceptionCount : 0;
            actualCount = actualCount > 0 ? actualCount : 0;

            attendance.setSupposedDays(supposedDays);
            attendance.setExceptionDays(exceptionDays);
            attendance.setActualDays(actualDays);

            attendance.setSupposedCount(supposedCount);
            attendance.setExceptionCount(exceptionCount);
            attendance.setActualCount(actualCount);

            attendance.setLeaveDays(leaveDays);
            attendance.setTravelDays(travelDays);
            attendance.setOutDays(outDays);
            attendance.setOvertimeHours(overtimeHours);
            attendance.setOvertimeDays(overtimeDays);
            attendance.setSupplementCount(supplementCount);
            attendance.setAnnualLeaveDays(annualLeaveDays);
            attendance.setMaritalLeaveDays(maritalLeaveDays);
            attendance.setMaternityLeaveDays(maternityLeaveDays);
            attendance.setNormalLeaveDays(normalLeaveDays);
            attendance.setOffLeaveDays(offLeaveDays);
            attendance.setOtherLeaveDays(otherLeaveDays);
            attendance.setPaternityLeaveDays(paternityLeaveDays);
            attendance.setSickLeaveDays(sickLeaveDays);
            attendance.setRemark(remark.toJSONString());

            result = attendanceService.insertOrUpdate(attendance);
            if (!result) {
                break;
            }
        }
        //获取该月
        return result;
    }

    @Override
    public boolean refreshCheckIn(int year, int month) {
        month = month - 1;
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, 1, 0, 0, 0);
        long beginTime = calendar.getTimeInMillis();
        int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(year, month, maxDay, 23, 59, 59);
        long endTime = calendar.getTimeInMillis();
        //首先删除
        EntityWrapper<HrCheckin> checkinEntityWrapper = new EntityWrapper<>();
        checkinEntityWrapper.where("checkin_time >=" + beginTime).and("checkin_time <" + endTime);
        checkinService.delete(checkinEntityWrapper);
        return checkinService.insertCheckinArray(beginTime / 1000, endTime / 1000);
    }

    /**
     * 每月1号凌晨1点执行一次
     */
    @Scheduled(cron = "0 0 1 1 * ?")
    @Override
    public void scheduler() {
        _log.info("每月同步考勤信息");
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH) + 1;
        int year = calendar.get(Calendar.YEAR);
        if (month >= 12) {
            year = year - 1;
        }
        countAttendance(year, month - 1);
    }
}
